/******************************************************************************
 *
 * Copyright:
 *    (C) 2006 Embedded Artists AB
 *
 * File:
 *    lcd.c
 *
 * Description:
 *    Implements routines for the LCD.
 *
 *****************************************************************************/

/******************************************************************************
 * Includes
 *****************************************************************************/
#include "../pre_emptive_os/api/general.h"
#include "../pre_emptive_os/api/osapi.h"
#include "lcd.h"
#include "lcd_hw.h"


/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/
#define LCD_CMD_SWRESET   0x01
#define LCD_CMD_BSTRON    0x03
#define LCD_CMD_SLEEPIN   0x10
#define LCD_CMD_SLEEPOUT  0x11
#define LCD_CMD_INVON     0x21
#define LCD_CMD_SETCON    0x25
#define LCD_CMD_DISPON    0x29
#define LCD_CMD_CASET     0x2A
#define LCD_CMD_PASET     0x2B
#define LCD_CMD_RAMWR     0x2C
#define LCD_CMD_RGBSET    0x2D
#define LCD_CMD_MADCTL    0x36
#define LCD_CMD_COLMOD    0x3A

#define MADCTL_HORIZ      0x48
#define MADCTL_VERT       0x68


/*****************************************************************************
 * Local variables
 ****************************************************************************/
static tU8 lcd_x;
static tU8 lcd_y;
static tU8 bkgColor;
static tU8 textColor;

/*****************************************************************************
 * Local prototypes
 ****************************************************************************/
static void lcdWindow1(tU8 xp, tU8 yp, tU8 xe, tU8 ye);


/*****************************************************************************
 *
 * Description:
 *    Initialize the LCD controller and SPI interface
 *    (0,0) is top left and (129,129) is bottom right
 *    8 bits Color mode uses RRRGGGBB layout
 *
 ****************************************************************************/
void lcdInit(void) {
	bkgColor = 0;
	textColor = 0;

	//init SPI interface
	initSpiForLcd();

	//select controller
	selectLCD(TRUE);

	lcdWrcmd(LCD_CMD_SWRESET);

	osSleep(1);
	lcdWrcmd(LCD_CMD_SLEEPOUT);
	lcdWrcmd(LCD_CMD_DISPON);
	lcdWrcmd(LCD_CMD_BSTRON);
	osSleep(1);

	lcdWrcmd(LCD_CMD_MADCTL); //Memory data acces control
	lcdWrdata(MADCTL_HORIZ); //X Mirror and BGR format
	lcdWrcmd(LCD_CMD_COLMOD); //Colour mode
	lcdWrdata(0x02); //256 colour mode select
	lcdWrcmd(LCD_CMD_INVON); //Non Invert mode

	lcdWrcmd(LCD_CMD_RGBSET); //LUT write
	lcdWrdata(0); //Red
	lcdWrdata(2);
	lcdWrdata(4);
	lcdWrdata(6);
	lcdWrdata(9);
	lcdWrdata(11);
	lcdWrdata(13);
	lcdWrdata(15);
	lcdWrdata(0); //Green
	lcdWrdata(2);
	lcdWrdata(4);
	lcdWrdata(6);
	lcdWrdata(9);
	lcdWrdata(11);
	lcdWrdata(13);
	lcdWrdata(15);
	lcdWrdata(0); //Blue
	lcdWrdata(6);
	lcdWrdata(10);
	lcdWrdata(15);

	//deselect controller
	selectLCD(FALSE);

	lcdContrast(56);

	lcdClrscr();
}


/*****************************************************************************
 *
 * Description:
 *    Clear screen (with current background color)
 *
 ****************************************************************************/
void lcdClrscr(void) {
	tU32 i;

	lcd_x = 0;
	lcd_y = 0;

	//select controller
	selectLCD(TRUE);

	lcdWindow1(255, 255, 128, 128);

	lcdWrcmd(LCD_CMD_RAMWR); //write memory

	for (i = 0; i < 16900; i++)
		lcdWrdata(bkgColor);

	//deselect controller
	selectLCD(FALSE);
}


/*****************************************************************************
 *
 * Description:
 *    Shut down the LCD controller
 *
 ****************************************************************************/
void lcdOff(void) {
	lcdClrscr();

	//select controller
	selectLCD(TRUE);

	lcdWrcmd(LCD_CMD_SLEEPIN);

	//deselect controller
	selectLCD(FALSE);
}


/*****************************************************************************
 *
 * Description:
 *    Set current foreground and background color
 *
 ****************************************************************************/
void lcdColor(tU8 bkg, tU8 text) {
	bkgColor = bkg;
	textColor = text;
}


/*****************************************************************************
 *
 * Description:
 *    Set display contrast
 *
 ****************************************************************************/
void lcdContrast(tU8 cont) //vary between 0 - 127
{
	//select controller
	selectLCD(TRUE);

	//set contrast cmd.
	lcdWrcmd(LCD_CMD_SETCON);
	lcdWrdata(cont);

	//deselect controller
	selectLCD(FALSE);
}


/*****************************************************************************
 *
 * Description:
 *    Draw a rectangular area with specified color.
 *
 ****************************************************************************/
void lcdRect(tU8 x, tU8 y, tU8 xLen, tU8 yLen, tU8 color) {
	tU32 i;
	tU32 len;

	//select controller
	selectLCD(TRUE);

	lcdWindow1(x, y, x + xLen - 1, y + yLen - 1);

	lcdWrcmd(LCD_CMD_RAMWR); //write memory

	len = xLen * yLen;
	for (i = 0; i < len; i++)
		lcdWrdata(color);

	//deselect controller
	selectLCD(FALSE);
}

void lcdDisplayBoatTilt(tU8 color, int boatTilt) {


	//select controller
	selectLCD(TRUE);

	lcdWindow1(0, 0, 128, 128);

	//clear screen
	lcdClrscr();

	lcdWrcmd(LCD_CMD_RAMWR); //write memory

	//vertical line denoting center of the screen
	lcdRect(64, 0, 2, 128, 4);

	//transform boat tilt according to the accelerometer position
	tU8 x = BOAT_X0_POSITION - BOAT_WIDTH/2 + boatTilt;
	if (x < 1) {
		x = 1;
	} else if (x > (128 - BOAT_WIDTH)) {
		x = 128 - BOAT_WIDTH;
	}
	lcdRect(x - BOAT_WIDTH/2, BOAT_Y0_POSITION - BOAT_LENGTH/2, BOAT_WIDTH, BOAT_LENGTH, 3);
	printf("after write\n");
	//deselect controller
	selectLCD(FALSE);
}


/*****************************************************************************
 *
 * Description:
 *    Update xy-position (by also creating a window).
 *
 ****************************************************************************/
void
lcdGotoxy(tU8 x, tU8 y)
{
  lcd_x = x;
  lcd_y = y;
  lcdWindow(x, y, 129, 129);
}


/*****************************************************************************
 *
 * Description:
 *    Initialize LCD controller for a window (to write in).
 *    Set start xy-position and xy-length.
 *    Selects/deselects LCD controller.
 *
 ****************************************************************************/
void lcdWindow(tU8 xp, tU8 yp, tU8 xe, tU8 ye) {
	//select controller
	selectLCD(TRUE);

	lcdWindow1(xp, yp, xe, ye);

	//deselect controller
	selectLCD(FALSE);
}


/*****************************************************************************
 *
 * Description:
 *    Initialize LCD controller for a window (to write in).
 *    Set start xy-position and xy-length
 *    No select/deselect of LCD controller.
 *
 ****************************************************************************/
static void lcdWindow1(tU8 xp, tU8 yp, tU8 xe, tU8 ye) {
	lcdWrcmd(LCD_CMD_CASET); //set X
	lcdWrdata(xp + 2);
	lcdWrdata(xe + 2);

	lcdWrcmd(LCD_CMD_PASET); //set Y
	lcdWrdata(yp + 2);
	lcdWrdata(ye + 2);
}



/*****************************************************************************
 *
 * Description:
 *    Send command data to LCD controller
 *
 ****************************************************************************/
void
lcdWrcmd(tU8 data)
{
  sendToLCD(0, data);
}


/*****************************************************************************
 *
 * Description:
 *    Send data byte to LCD controller
 *
 ****************************************************************************/
void
lcdWrdata(tU8 data)
{
  sendToLCD(1, data);
}


